import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/foundation.dart' show kIsWeb, defaultTargetPlatform, TargetPlatform;
import 'package:chewie/chewie.dart';
import 'package:video_player/video_player.dart';
import 'package:video_player_win/video_player_win.dart' as winvp;
import 'package:flutter/services.dart';
import 'package:window_manager/window_manager.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:http/http.dart' as http;
import 'package:wakelock_plus/wakelock_plus.dart';
import 'package:cached_network_image/cached_network_image.dart';
import '../core/history.dart';
import '../core/models.dart';
import '../core/media_control_event_bus.dart';
import '../widgets/tv_focus_wrapper.dart';

class PlayerPage extends StatefulWidget {
  final String name;
  final String title;
  final String url;
  final String? cover; // 封面图URL
  final String? year;
  final String? sourceSite; // 播放源站点名称
  final List<PlayEpisode>? searchResults; // 扁平化剧集（可选，兼容旧入口）
  final List<PlaySource>? playSources; // 分组播放源与剧集（推荐）
  const PlayerPage({
    super.key,
    required this.name,
    required this.title,
    required this.url,
    this.cover,
    this.year,
    this.sourceSite,
    this.searchResults,
    this.playSources,
  });

  @override
  State<PlayerPage> createState() => _PlayerPageState();
}

class _PlayerPageState extends State<PlayerPage> {
  VideoPlayerController? _videoController;
  ChewieController? _chewieController;
  winvp.WinVideoPlayerController? _winController;
  bool _initializing = true;
  String? _error;
  int _selectedSourceIndex = 0;
  bool _didInferSelectedSource = false;
  late String _currentUrl;
  late String _currentTitle;
  int _initToken = 0;
  bool _closing = false;
  bool _autoNextTriggered = false;
  bool _resumeFullScreenAfterSwitch = false;
  double _loadingProgress = 0.0;
  int _panelTab = 0;
  bool _episodesAsc = true;
  
  // 媒体控制事件监听器
  MediaControlListener? _mediaControlListener;

  @override
  void initState() {
    super.initState();
    _currentUrl = widget.url;
    _currentTitle = widget.title;
    _initForUrl(_currentUrl);
    _setupMediaControlListener();
    () async {
      try {
        await WakelockPlus.enable();
      } catch (_) {}
    }();
  }

  Future<void> _initForUrl(String url) async {
    print('初始化播放url: $url');
    final int token = ++_initToken;
    bool success = false;
    _error = null;
    try {
      final resolved = await _resolvePlayableUrl(url);
      if (!mounted || _closing || token != _initToken) return;
      final isWindows = !kIsWeb && defaultTargetPlatform == TargetPlatform.windows;
      if (isWindows) {
        final ctrl = winvp.WinVideoPlayerController.networkUrl(Uri.parse(resolved));
        await ctrl.initialize();
        if (!mounted || _closing || token != _initToken) {
          try { await ctrl.dispose(); } catch (_) {}
          return;
        }
        _winController = ctrl;
        _winController!.addListener(_onWinControllerChanged);
        await ctrl.play();
        success = true;
      } else {
        final ctrl = VideoPlayerController.networkUrl(Uri.parse(resolved));
        await ctrl.initialize();
        if (!mounted || _closing || token != _initToken) {
          try { await ctrl.dispose(); } catch (_) {}
          return;
        }
        if (!ctrl.value.isInitialized) {
          throw StateError('播放器未初始化，可能是流格式不支持或网络不可达');
        }
        _videoController = ctrl;
        _chewieController = ChewieController(
          videoPlayerController: ctrl,
          autoPlay: true,
          looping: false,
          allowFullScreen: false,
          allowPlaybackSpeedChanging: true,
          deviceOrientationsOnEnterFullScreen: const [
            DeviceOrientation.landscapeLeft,
            DeviceOrientation.landscapeRight,
          ],
          deviceOrientationsAfterFullScreen: const [
            DeviceOrientation.portraitUp,
          ],
        );
        _videoController!.addListener(_onVideoControllerChanged);
        success = true;
      }
      // 记录播放历史
      final now = DateTime.now().millisecondsSinceEpoch ~/ 1000;
      await HistoryStore.add(PlayHistoryItem(
        name: widget.name,
        title: _currentTitle,
        url: _currentUrl,
        siteName: null,
        cover: widget.cover,
        sourceSite: widget.sourceSite,
        time: now,
      ));
    } catch (e) {
      _error = '播放初始化失败: $e';
    } finally {
      if (mounted && token == _initToken && !_closing) {
        setState(() {
          _initializing = false;
          if (success) _error = null;
          _autoNextTriggered = false;
        });
        if (success && _resumeFullScreenAfterSwitch) {
          _resumeFullScreenAfterSwitch = false;
          Future.microtask(() => _onFullScreenPressed());
        }
      }
    }
  }

  void _onVideoControllerChanged() {
    try {
      final v = _videoController?.value;
      final dur = v?.duration;
      final pos = v?.position;
      if (v == null || dur == null || pos == null) return;
      if (dur.inMilliseconds > 0 && pos >= dur - const Duration(milliseconds: 500)) {
        if (!_autoNextTriggered) {
          _autoNextTriggered = true;
          Future.microtask(() => _playNextEpisode());
        }
      }
    } catch (_) {}
  }

  void _onWinControllerChanged() {
    try {
      final v = _winController?.value;
      final dur = v?.duration;
      final pos = v?.position;
      if (v == null || dur == null || pos == null) return;
      if (dur.inMilliseconds > 0 && pos >= dur - const Duration(milliseconds: 500)) {
        if (!_autoNextTriggered) {
          _autoNextTriggered = true;
          Future.microtask(() => _playNextEpisode());
        }
      }
    } catch (_) {}
  }

  Future<String> _resolvePlayableUrl(String url) async {
    final uri = Uri.tryParse(url);
    if (uri == null) return url;
    final host = uri.host;
    final path = uri.path;
    if (host.contains('rsfcxq.com') && path.startsWith('/share/')) {
      try {
        final resp = await http.get(uri, headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0 Safari/537.36',
          'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        }).timeout(const Duration(seconds: 10));
        final body = resp.body;
        final matches = RegExp(r'https?://\S+').allMatches(body).map((mm) => mm.group(0)!).toList();
        for (final link in matches) {
          final cleaned = link.replaceAll(RegExp("[\\\"'\\)\\],>]+\$"), "");
          final lower = cleaned.toLowerCase();
          if (lower.contains('.m3u8') || lower.contains('.mp4')) {
            return cleaned;
          }
        }
        final redirected = resp.request?.url.toString();
        if (redirected != null && redirected != url) {
          return redirected;
        }
      } catch (_) {}
    }
    return url;
  }

  // 设置媒体控制事件监听器
  void _setupMediaControlListener() {
    _mediaControlListener = (event) {
      switch (event) {
        case MediaControlEvent.playPause:
          _handlePlayPause();
          break;
        case MediaControlEvent.stop:
          _handleStop();
          break;
        case MediaControlEvent.rewind:
          _handleRewind();
          break;
        case MediaControlEvent.fastForward:
          _handleFastForward();
          break;
        case MediaControlEvent.volumeUp:
          _handleVolumeUp();
          break;
        case MediaControlEvent.volumeDown:
          _handleVolumeDown();
          break;
        case MediaControlEvent.mute:
          _handleMute();
          break;
        case MediaControlEvent.nextTrack:
        case MediaControlEvent.previousTrack:
          // 下一曲/上一曲功能在播放器页面中暂不实现
          break;
      }
    };
    MediaControlEventBus.instance.addListener(_mediaControlListener!);
  }

  // 移除媒体控制事件监听器
  void _removeMediaControlListener() {
    if (_mediaControlListener != null) {
      MediaControlEventBus.instance.removeListener(_mediaControlListener!);
      _mediaControlListener = null;
    }
  }

  // 处理播放/暂停事件
  void _handlePlayPause() {
    if (_chewieController != null && _chewieController!.isPlaying) {
      _chewieController!.pause();
    } else if (_chewieController != null && !_chewieController!.isPlaying) {
      _chewieController!.play();
    }
  }

  // 处理停止事件
  void _handleStop() {
    if (_chewieController != null) {
      _chewieController!.pause();
      _chewieController!.seekTo(Duration.zero);
    }
  }

  // 处理快退事件
  void _handleRewind() {
    if (_chewieController != null) {
      final currentPosition = _chewieController!.videoPlayerController.value.position;
      final newPosition = currentPosition - const Duration(seconds: 10);
      _chewieController!.seekTo(newPosition > Duration.zero ? newPosition : Duration.zero);
    }
  }

  // 处理快进事件
  void _handleFastForward() {
    if (_chewieController != null) {
      final currentPosition = _chewieController!.videoPlayerController.value.position;
      final duration = _chewieController!.videoPlayerController.value.duration;
      if (duration != null) {
        final newPosition = currentPosition + const Duration(seconds: 10);
        _chewieController!.seekTo(newPosition < duration ? newPosition : duration);
      }
    }
  }

  // 处理音量增加事件
  void _handleVolumeUp() {
    if (_chewieController != null) {
      final currentVolume = _chewieController!.videoPlayerController.value.volume;
      final newVolume = (currentVolume + 0.1).clamp(0.0, 1.0);
      _chewieController!.videoPlayerController.setVolume(newVolume);
    }
  }

  // 处理音量减少事件
  void _handleVolumeDown() {
    if (_chewieController != null) {
      final currentVolume = _chewieController!.videoPlayerController.value.volume;
      final newVolume = (currentVolume - 0.1).clamp(0.0, 1.0);
      _chewieController!.videoPlayerController.setVolume(newVolume);
    }
  }

  // 处理静音事件
  void _handleMute() {
    if (_chewieController != null) {
      final currentVolume = _chewieController!.videoPlayerController.value.volume;
      if (currentVolume > 0) {
        _chewieController!.videoPlayerController.setVolume(0);
      } else {
        _chewieController!.videoPlayerController.setVolume(1.0);
      }
    }
  }

  @override
  void dispose() {
    _closing = true;
    _initToken++;
    _removeMediaControlListener();
    _chewieController?.dispose();
    _videoController?.dispose();
    _winController?.dispose();
    () async {
      try {
        await WakelockPlus.disable();
      } catch (_) {}
    }();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    final isWide = width >= 900;
    final hasSources = (widget.playSources != null && widget.playSources!.isNotEmpty) ||
        (widget.searchResults != null && widget.searchResults!.isNotEmpty);
    // 根据当前播放URL推断默认选中的源（仅首次推断，避免覆盖用户选择）
    if (!_didInferSelectedSource && widget.playSources != null && widget.playSources!.isNotEmpty) {
      final idx = widget.playSources!.indexWhere((src) => src.episodes.any((e) => e.url == _currentUrl));
      if (idx >= 0) {
        _selectedSourceIndex = idx;
      }
      _selectedSourceIndex = _selectedSourceIndex.clamp(0, widget.playSources!.length - 1);
      _didInferSelectedSource = true;
    }
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.background,
      body: WillPopScope(
        onWillPop: () async {
          _closing = true;
          _initToken++;
          await _disposeControllers();
          return true;
        },
        child: SafeArea(
          child: Column(
            children: [
              // 顶部导航栏
              _buildTechAppBar(),

            // 主体区域：宽屏右侧显示播放源；窄屏在播放器下方显示
            Expanded(
              child: isWide
                  ? Row(
                      children: [
                        // 视频播放区域
                        Expanded(
                          child: Container(
                            margin: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                              borderRadius: BorderRadius.circular(16),
                              color: Theme.of(context).colorScheme.surface,
                              boxShadow: [
                                BoxShadow(
                                  color: Theme.of(context).colorScheme.primary.withOpacity(0.12),
                                  blurRadius: 20,
                                  spreadRadius: 2,
                                ),
                              ],
                            ),
                            child: ClipRRect(
                              borderRadius: BorderRadius.circular(16),
                              child: _buildVideoPlayer(),
                            ),
                          ),
                        ),

                        if (hasSources)
                          Container(
                            width: 380,
                            margin: const EdgeInsets.all(8),
                            child: _buildSourcePanelRight(),
                          ),
                      ],
                    )
                  : Column(
                      children: [
                        // 视频播放区域
                        Container(
                          margin: const EdgeInsets.all(8),
                          decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(16),
                            color: Theme.of(context).colorScheme.surface,
                            boxShadow: [
                              BoxShadow(
                                color: Theme.of(context).colorScheme.primary.withOpacity(0.12),
                                blurRadius: 20,
                                spreadRadius: 2,
                              ),
                            ],
                          ),
                          child: ClipRRect(
                            borderRadius: BorderRadius.circular(16),
                            child: AspectRatio(
                              aspectRatio: (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows)
                                  ? (_winController?.value.aspectRatio ?? (16 / 9))
                                  : (_videoController?.value.aspectRatio ?? (16 / 9)),
                              child: _buildVideoPlayer(),
                            ),
                          ),
                        ),

                        if (hasSources)
                          Expanded(
                            child: Container(
                              margin: const EdgeInsets.symmetric(horizontal: 8),
                              child: _buildSourcePanelBelow(),
                            ),
                          ),
                      ],
                    ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildTechAppBar() {
    return Container(
      height: 60,
      margin: const EdgeInsets.all(8),
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(
          color: Theme.of(context).colorScheme.outline.withOpacity(0.3),
          width: 1,
        ),
      ),
      child: Row(
        children: [
          // 返回按钮
          IconButton(
            onPressed: () async {
              _closing = true;
              _initToken++;
              await _disposeControllers();
              if (mounted) {
                Navigator.pop(context);
              }
            },
            icon: Icon(
              Icons.arrow_back_ios,
              color: Theme.of(context).colorScheme.onSurface,
              size: 20,
            ),
          ),
          
          // 标题 - 使用更灵活的布局确保站点名称显示完整
          Expanded(
            flex: 1,
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 8),
              child: Text(
                _currentTitle,
                style: TextStyle(
                  color: Theme.of(context).colorScheme.onSurface,
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
                overflow: TextOverflow.ellipsis,
                maxLines: 1,
                softWrap: false,
              ),
            ),
          ),
          Builder(
            builder: (context) {
              final bool canFullScreen = (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows)
                  ? _winController != null
                  : _chewieController != null;
              return Padding(
                padding: const EdgeInsets.only(right: 8),
                child: TextButton.icon(
                  onPressed: canFullScreen ? _onFullScreenPressed : null,
                  label: Text(
                    '全屏播放',
                    style: TextStyle(
                      color: Theme.of(context).colorScheme.onSurface,
                    ),
                  ),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.red[600],
                    foregroundColor: Colors.white,
                    padding: const EdgeInsets.symmetric(vertical: 16),
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(12),
                    ),
                    elevation: 2,
                 ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }

  Future<void> _onFullScreenPressed() async {
    final isWindows = !kIsWeb && defaultTargetPlatform == TargetPlatform.windows;
    if (isWindows) {
      if (_winController == null) return;
      try {
        await windowManager.setFullScreen(true);
      } catch (_) {}
      await Navigator.of(context).push(
        MaterialPageRoute(builder: (_) => _FullScreenWin(controller: _winController!)),
      );
      try {
        await windowManager.setFullScreen(false);
      } catch (_) {}
    } else {
      if (_chewieController == null || _videoController == null) return;
      await Navigator.of(context).push(
        MaterialPageRoute(
          builder: (_) => _FullScreenChewie(
            controller: _chewieController!,
            videoController: _videoController!,
          ),
        ),
      );
    }
  }

  /// 构建视频播放器
  Widget _buildVideoPlayer() {
    return Center(
      child: _initializing
          ? _buildLoadingIndicator()
          : _error != null
              ? _buildErrorWidget()
              : (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows)
                  ? AspectRatio(
                      aspectRatio: _winController?.value.aspectRatio ?? (16 / 9),
                      child: (_winController == null)
                          ? _buildLoadingIndicator()
                          : Stack(
                              alignment: Alignment.bottomCenter,
                              children: [
                                GestureDetector(
                                  onTap: () async {
                                    if (_winController!.value.isPlaying ?? false) {
                                      await _winController!.pause();
                                    } else {
                                      await _winController!.play();
                                    }
                                  },
                                  child: winvp.WinVideoPlayer(_winController!),
                                ),
                                _WinControls(controller: _winController!),
                              ],
                            ),
                    )
                  : (() {
                      final bool ready = _videoController != null && _chewieController != null && _videoController!.value.isInitialized;
                      final double arRaw = _videoController?.value.aspectRatio ?? 0;
                      final double ar = arRaw == 0 ? 16 / 9 : arRaw;
                      return AspectRatio(
                        aspectRatio: ar,
                        child: ready
                            ? GestureDetector(
                                onTap: () {
                                  if (_videoController!.value.isPlaying) {
                                    _videoController!.pause();
                                  } else {
                                    _videoController!.play();
                                  }
                                },
                                child: Chewie(controller: _chewieController!),
                              )
                            : _buildLoadingIndicator(),
                      );
                    })(),
    );
  }

  /// 构建科技感加载指示器
  Widget _buildLoadingIndicator() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Container(
          width: 80,
          height: 80,
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(40),
            color: Theme.of(context).colorScheme.primaryContainer,
          ),
          child: const Center(
            child: CircularProgressIndicator(
              strokeWidth: 3,
              valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
            ),
          ),
        ),
        const SizedBox(height: 24),
        Text(
          '正在加载影视...',
          style: TextStyle(
            color: Theme.of(context).colorScheme.onSurfaceVariant,
            fontSize: 16,
            fontWeight: FontWeight.w500,
          ),
        ),
      ],
    );
  }

  /// 构建错误提示组件
  Widget _buildErrorWidget() {
    return Container(
      padding: const EdgeInsets.all(24),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Icon(
            Icons.error_outline,
            color: Theme.of(context).colorScheme.error,
            size: 64,
          ),
          const SizedBox(height: 16),
          Text(
            '播放失败',
            style: TextStyle(
              color: Theme.of(context).colorScheme.error,
              fontSize: 18,
              fontWeight: FontWeight.bold,
            ),
          ),
          const SizedBox(height: 8),
          Text(
            _error!,
            style: TextStyle(
              color: Theme.of(context).colorScheme.onSurfaceVariant,
              fontSize: 14,
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 16),
          Wrap(
            spacing: 12,
            runSpacing: 8,
            alignment: WrapAlignment.center,
            children: [
              OutlinedButton.icon(
                onPressed: _retryInit,
                icon: const Icon(Icons.refresh_rounded),
                label: const Text('重试或换源'),
              ),
              OutlinedButton.icon(
                onPressed: _openInBrowser,
                icon: const Icon(Icons.open_in_browser_rounded),
                label: const Text('浏览器打开'),
              ),
              OutlinedButton.icon(
                onPressed: _copyCurrentLink,
                icon: const Icon(Icons.link_rounded),
                label: const Text('复制链接'),
              ),
            ],
          ),
        ],
      ),
    );
  }

  /// 右侧播放源面板：左列播放源，右列剧集
  Widget _buildSourcePanelRight() {
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).colorScheme.surface,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: Theme.of(context).colorScheme.outline.withOpacity(0.2), width: 1),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.surfaceVariant,
              borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
            ),
            child: Row(
              children: [
                Expanded(
                  child: GestureDetector(
                    onTap: () => setState(() => _panelTab = 0),
                    child: Container(
                      padding: const EdgeInsets.symmetric(vertical: 10),
                      decoration: BoxDecoration(
                        color: _panelTab == 0 ? Theme.of(context).colorScheme.primaryContainer : Colors.transparent,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      alignment: Alignment.center,
                      child: Text(
                        '选集',
                        style: TextStyle(
                          color: _panelTab == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onSurfaceVariant,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: GestureDetector(
                    onTap: () => setState(() => _panelTab = 1),
                    child: Container(
                      padding: const EdgeInsets.symmetric(vertical: 10),
                      decoration: BoxDecoration(
                        color: _panelTab == 1 ? Theme.of(context).colorScheme.primaryContainer : Colors.transparent,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      alignment: Alignment.center,
                      child: Text(
                        '换源',
                        style: TextStyle(
                          color: _panelTab == 1 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onSurfaceVariant,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(10),
              child: _panelTab == 0 ? _buildEpisodesGrid() : _buildSourcesListEnhanced(),
            ),
          ),
        ],
      ),
    );
  }

  /// 窄屏下的播放源面板（放在播放器下方）
  Widget _buildSourcePanelBelow() {
    return Container(
      constraints: BoxConstraints(
        maxHeight: MediaQuery.of(context).size.height * 0.5,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
            decoration: BoxDecoration(
              color: Theme.of(context).colorScheme.surfaceVariant,
              borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
            ),
            child: Row(
              children: [
                Expanded(
                  child: GestureDetector(
                    onTap: () => setState(() => _panelTab = 0),
                    child: Container(
                      padding: const EdgeInsets.symmetric(vertical: 10),
                      decoration: BoxDecoration(
                        color: _panelTab == 0 ? Theme.of(context).colorScheme.primaryContainer : Colors.transparent,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      alignment: Alignment.center,
                      child: Text(
                        '选集',
                        style: TextStyle(
                          color: _panelTab == 0 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onSurfaceVariant,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                ),
                Expanded(
                  child: GestureDetector(
                    onTap: () => setState(() => _panelTab = 1),
                    child: Container(
                      padding: const EdgeInsets.symmetric(vertical: 10),
                      decoration: BoxDecoration(
                        color: _panelTab == 1 ? Theme.of(context).colorScheme.primaryContainer : Colors.transparent,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      alignment: Alignment.center,
                      child: Text(
                        '换源',
                        style: TextStyle(
                          color: _panelTab == 1 ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.onSurfaceVariant,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                    ),
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(10),
              child: _panelTab == 0 ? _buildEpisodesGrid() : _buildSourcesListEnhanced(),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildEpisodesGrid() {
    final sources = widget.playSources ?? [];
    if (sources.isEmpty) {
      return Center(child: Text('无播放源', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant)));
    }
    final group = sources[_selectedSourceIndex];
    final eps = List<PlayEpisode>.from(group.episodes);
    final ordered = _episodesAsc ? eps : eps.reversed.toList();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Row(
          children: [
            Text('1-${group.episodes.length}', style: TextStyle(color: Theme.of(context).colorScheme.primary, fontWeight: FontWeight.bold)),
            const SizedBox(width: 8),
            Expanded(child: Container(height: 1, color: Theme.of(context).colorScheme.outline.withOpacity(0.2))),
            IconButton(
              onPressed: () => setState(() => _episodesAsc = !_episodesAsc),
              icon: const Icon(Icons.swap_vert),
            ),
          ],
        ),
        const SizedBox(height: 8),
        Expanded(
          child: SingleChildScrollView(
            child: Wrap(
              spacing: 10,
              runSpacing: 10,
              children: [
                for (final ep in ordered)
                  _episodeChip(ep, isCurrent: ep.url == _currentUrl),
              ],
            ),
          ),
        ),
      ],
    );
  }

  Widget _episodeChip(PlayEpisode ep, {required bool isCurrent}) {
    return InkWell(
      onTap: isCurrent ? null : () => _switchSource(ep),
      child: Container(
        decoration: BoxDecoration(
          color: isCurrent ? Theme.of(context).colorScheme.primaryContainer : Theme.of(context).colorScheme.surfaceVariant,
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: isCurrent ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.outline.withOpacity(0.2), width: 1),
        ),
        padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
        child: Text(
          ep.title,
          style: TextStyle(
            color: isCurrent ? Theme.of(context).colorScheme.onPrimaryContainer : Theme.of(context).colorScheme.onSurfaceVariant,
            fontWeight: FontWeight.w600,
          ),
        ),
      ),
    );
  }

  Widget _buildSourcesListEnhanced() {
    final sources = widget.playSources ?? [];
    return ListView.separated(
      itemCount: sources.length,
      separatorBuilder: (_, __) => const SizedBox(height: 8),
      itemBuilder: (context, index) {
        final group = sources[index];
        final selected = index == _selectedSourceIndex;
        return InkWell(
          onTap: () => setState(() => _selectedSourceIndex = index),
          child: Container(
            padding: const EdgeInsets.all(10),
            decoration: BoxDecoration(
              color: selected ? Theme.of(context).colorScheme.primaryContainer : Theme.of(context).colorScheme.surfaceVariant,
              borderRadius: BorderRadius.circular(12),
              border: Border.all(
                color: selected ? Theme.of(context).colorScheme.primary : Theme.of(context).colorScheme.outline.withOpacity(0.2),
                width: 1,
              ),
            ),
            child: Row(
              children: [
                SizedBox(
                  width: 44,
                  height: 64,
                  child: ClipRRect(
                    borderRadius: BorderRadius.circular(8),
                    child: (widget.cover != null && widget.cover!.isNotEmpty)
                        ? CachedNetworkImage(
                            imageUrl: widget.cover!,
                            fit: BoxFit.cover,
                            httpHeaders: const {
                              'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                              'Referer': 'https://movie.douban.com/',
                            },
                          )
                        : Container(color: Theme.of(context).colorScheme.surface),
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        children: [
                          Expanded(
                            child: Builder(
                              builder: (_) {
                                final baseName = widget.title.split(' · ').first;
                                final displayTitle = (widget.year != null && widget.year!.isNotEmpty)
                                    ? '$baseName ${widget.year}'
                                    : baseName;
                                return Text(
                                  displayTitle,
                                  style: TextStyle(
                                    color: selected ? Theme.of(context).colorScheme.onPrimaryContainer : Theme.of(context).colorScheme.onSurface,
                                    fontWeight: FontWeight.w600,
                                  ),
                                  overflow: TextOverflow.ellipsis,
                                );
                              },
                            ),
                          ),
                          Container(
                            padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
                            decoration: BoxDecoration(
                              color: Theme.of(context).colorScheme.surface,
                              borderRadius: BorderRadius.circular(10),
                            ),
                            child: Text('${group.episodes.length} 集', style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant, fontSize: 12)),
                          ),
                        ],
                      ),
                      const SizedBox(height: 6),
                      Wrap(
                        spacing: 8,
                        runSpacing: 4,
                        children: [
                          if ((group.siteName ?? '').isNotEmpty)
                            Container(
                              padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
                              decoration: BoxDecoration(
                                color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
                                borderRadius: BorderRadius.circular(8),
                              ),
                              child: Text(group.siteName!, style: TextStyle(color: Theme.of(context).colorScheme.primary, fontSize: 11)),
                            ),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }

  /// 切换具体剧集
  Future<void> _disposeControllers() async {
    try {
      _initToken++;
      if (!kIsWeb && defaultTargetPlatform == TargetPlatform.windows) {
        try { _winController?.removeListener(_onWinControllerChanged); } catch (_) {}
        try { await _winController?.pause(); } catch (_) {}
        await _winController?.dispose();
        _winController = null;
      } else {
        try { _videoController?.removeListener(_onVideoControllerChanged); } catch (_) {}
        try { await _videoController?.pause(); } catch (_) {}
        _chewieController?.dispose();
        await _videoController?.dispose();
        _chewieController = null;
        _videoController = null;
      }
    } catch (_) {}
  }

  Future<void> _retryInit() async {
    setState(() {
      _initializing = true;
      _error = null;
    });
    await _disposeControllers();
    await _initForUrl(_currentUrl);
  }

  Future<void> _openInBrowser() async {
    final uri = Uri.tryParse(_currentUrl);
    if (uri == null) return;
    try {
      await launchUrl(uri, mode: LaunchMode.externalApplication);
    } catch (_) {}
  }

  Future<void> _copyCurrentLink() async {
    try {
      await Clipboard.setData(ClipboardData(text: _currentUrl));
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已复制播放链接')));
      }
    } catch (_) {}
  }

  /// 就地切换剧集，避免路由动画引起抖动与旧音频残留
  Future<void> _switchSource(PlayEpisode source) async {
    setState(() {
      _initializing = true;
      _currentUrl = source.url;
      final base = widget.title.split(' · ').first;
      _currentTitle = '$base · ${source.title}';
      _error = null;
      _autoNextTriggered = false;
    });
    await _disposeControllers();
    await _initForUrl(_currentUrl);
  }

  Future<void> _playNextEpisode() async {
    final sources = widget.playSources ?? [];
    if (sources.isEmpty) return;
    // 如果当前页面不是顶层（例如全屏页在顶部），先退出顶部路由，切换后再恢复全屏
    if (ModalRoute.of(context)?.isCurrent == false) {
      _resumeFullScreenAfterSwitch = true;
      try { Navigator.of(context).pop(); } catch (_) {}
    }
    int groupIdx = sources.indexWhere((g) => g.episodes.any((e) => e.url == _currentUrl));
    if (groupIdx < 0) groupIdx = _selectedSourceIndex;
    groupIdx = groupIdx.clamp(0, sources.length - 1);
    final group = sources[groupIdx];
    final epIdx = group.episodes.indexWhere((e) => e.url == _currentUrl);
    if (epIdx >= 0 && epIdx + 1 < group.episodes.length) {
      final next = group.episodes[epIdx + 1];
      _selectedSourceIndex = groupIdx;
      await _switchSource(next);
      return;
    }
    if (groupIdx + 1 < sources.length && sources[groupIdx + 1].episodes.isNotEmpty) {
      _selectedSourceIndex = groupIdx + 1;
      await _switchSource(sources[_selectedSourceIndex].episodes.first);
    }
  }
}

class _WinControls extends StatefulWidget {
  final winvp.WinVideoPlayerController controller;
  const _WinControls({required this.controller});

  @override
  State<_WinControls> createState() => _WinControlsState();
}

class _WinControlsState extends State<_WinControls> {
  double _volume = 1.0;
  double _speed = 1.0;
  bool _fullscreen = false;

  @override
  void initState() {
    super.initState();
    _volume = widget.controller.value.volume ?? 1.0;
    _speed = widget.controller.value.playbackSpeed ?? 1.0;
    widget.controller.addListener(_onChanged);
  }

  @override
  void dispose() {
    widget.controller.removeListener(_onChanged);
    super.dispose();
  }

  void _onChanged() {
    final v = widget.controller.value;
    if (!mounted) return;
    setState(() {
      _volume = v.volume ?? _volume;
      _speed = v.playbackSpeed ?? _speed;
    });
  }

  Duration _duration() => widget.controller.value.duration ?? Duration.zero;
  Duration _position() => widget.controller.value.position ?? Duration.zero;
  bool _isPlaying() => widget.controller.value.isPlaying ?? false;

  Future<void> _seekTo(double seconds) async {
    await widget.controller.seekTo(Duration(seconds: seconds.round()));
  }

  @override
  Widget build(BuildContext context) {
    final double total = _duration().inSeconds.toDouble();
    final double pos = (_position().inSeconds.toDouble().clamp(0, total) as num).toDouble();
    return LayoutBuilder(
      builder: (context, constraints) {
        final isNarrow = constraints.maxWidth < 420;
        return Container(
          padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
          color: const Color(0x66000000),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Slider(
                value: pos,
                max: total <= 0 ? 1.0 : total,
                onChanged: (v) => _seekTo(v),
              ),
              Builder(
                builder: (context) {
                  final double scale = (constraints.maxWidth / 420).clamp(0.6, 1.0);
                  final double iconSize = 26.0 * scale;
                  final double volIconSize = 18.0 * scale;
                  final double gap = 8.0 * scale;
                  final double textSize = 12.0 * scale;
                  return Row(
                    children: [
                      IconButton(
                        iconSize: iconSize,
                        icon: Icon(_isPlaying() ? Icons.pause_rounded : Icons.play_arrow_rounded, color: Colors.white),
                        onPressed: () async {
                          if (_isPlaying()) {
                            await widget.controller.pause();
                          } else {
                            await widget.controller.play();
                          }
                        },
                      ),
                      IconButton(
                        iconSize: iconSize,
                        icon: const Icon(Icons.replay_10_rounded, color: Colors.white),
                        onPressed: () async {
                          final double newPos = ((_position() - const Duration(seconds: 10)).inSeconds.toDouble().clamp(0, total) as num).toDouble();
                          await _seekTo(newPos);
                        },
                      ),
                      IconButton(
                        iconSize: iconSize,
                        icon: const Icon(Icons.forward_10_rounded, color: Colors.white),
                        onPressed: () async {
                          final double newPos = ((_position() + const Duration(seconds: 10)).inSeconds.toDouble().clamp(0, total) as num).toDouble();
                          await _seekTo(newPos);
                        },
                      ),
                      SizedBox(width: gap),
                      Icon(Icons.volume_up_rounded, color: Colors.white, size: volIconSize),
                      SizedBox(width: gap),
                      Flexible(
                        fit: FlexFit.tight,
                        child: Slider(
                          value: _volume,
                          min: 0,
                          max: 1,
                          onChanged: (v) async {
                            if (!mounted) return;
                            setState(() => _volume = v);
                            try {
                              await widget.controller.setVolume(v);
                            } catch (_) {}
                          },
                        ),
                      ),
                      SizedBox(width: gap),
                      DropdownButtonHideUnderline(
                        child: DropdownButton<double>(
                          value: _speed,
                          dropdownColor: const Color(0xFF222222),
                          items: const [0.5, 1.0, 1.25, 1.5, 2.0]
                              .map((s) => DropdownMenuItem(value: s, child: Text('${s}x', style: TextStyle(color: Colors.white, fontSize: textSize))))
                              .toList(),
                          onChanged: (v) async {
                            if (v == null) return;
                            if (!mounted) return;
                            setState(() => _speed = v);
                            try {
                              await widget.controller.setPlaybackSpeed(v);
                            } catch (_) {}
                          },
                        ),
                      ),
                      const Spacer(),
                      IconButton(
                        iconSize: iconSize,
                        icon: Icon(_fullscreen ? Icons.fullscreen_exit_rounded : Icons.fullscreen_rounded, color: Colors.white),
                        onPressed: () async {
                          if (!mounted) return;
                          setState(() => _fullscreen = !_fullscreen);
                          if (_fullscreen) {
                            try {
                              await windowManager.setFullScreen(true);
                            } catch (_) {}
                            await Navigator.of(context).push(MaterialPageRoute(builder: (_) => _FullScreenWin(controller: widget.controller)));
                            try {
                              await windowManager.setFullScreen(false);
                            } catch (_) {}
                            if (!mounted) return;
                            setState(() => _fullscreen = false);
                          }
                        },
                      ),
                      SizedBox(width: gap / 2),
                      Text(
                        '${_format(_position())} / ${_format(_duration())}',
                        style: TextStyle(color: Colors.white, fontSize: textSize),
                      ),
                    ],
                  );
                },
              ),
            ],
          ),
        );
      },
    );
  }

  String _format(Duration d) {
    String two(int n) => n.toString().padLeft(2, '0');
    final h = two(d.inHours);
    final m = two(d.inMinutes % 60);
    final s = two(d.inSeconds % 60);
    return h == '00' ? '$m:$s' : '$h:$m:$s';
  }
}

class _FullScreenWin extends StatefulWidget {
  final winvp.WinVideoPlayerController controller;
  const _FullScreenWin({required this.controller});

  @override
  State<_FullScreenWin> createState() => _FullScreenWinState();
}

class _FullScreenWinState extends State<_FullScreenWin> {
  bool _showControls = false;
  Timer? _hideTimer;

  @override
  void initState() {
    super.initState();
    // 初始显示控制器，3秒后自动隐藏
    _showControls = true;
    _startHideTimer();
    () async {
      try {
        await windowManager.setFullScreen(true);
      } catch (_) {}
    }();
  }

  @override
  void dispose() {
    _hideTimer?.cancel();
    () async {
      try {
        await windowManager.setFullScreen(false);
      } catch (_) {}
    }();
    super.dispose();
  }

  void _startHideTimer() {
    _hideTimer?.cancel();
    _hideTimer = Timer(const Duration(seconds: 3), () {
      if (mounted) {
        setState(() => _showControls = false);
      }
    });
  }

  void _showControlsTemporarily() {
    setState(() => _showControls = true);
    _startHideTimer();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: RawKeyboardListener(
        focusNode: FocusNode(),
        autofocus: true,
        onKey: (event) {
          if (event is RawKeyDownEvent && event.logicalKey == LogicalKeyboardKey.escape) {
            Navigator.of(context).pop();
          }
        },
        child: MouseRegion(
          onHover: (_) => _showControlsTemporarily(),
          child: Stack(
            children: [
              Center(
                child: AspectRatio(
                  aspectRatio: widget.controller.value.aspectRatio ?? (16 / 9),
                  child: GestureDetector(
                    onTap: () async {
                      // 点击视频区域暂停/播放
                      if (widget.controller.value.isPlaying ?? false) {
                        await widget.controller.pause();
                      } else {
                        await widget.controller.play();
                      }
                      _showControlsTemporarily();
                    },
                    child: winvp.WinVideoPlayer(widget.controller),
                  ),
                ),
              ),
              // 顶部退出按钮
              AnimatedPositioned(
                duration: const Duration(milliseconds: 300),
                top: _showControls ? 8 : -60,
                right: 8,
                child: IconButton(
                  icon: const Icon(Icons.fullscreen_exit_rounded, color: Colors.white, size: 28),
                  onPressed: () => Navigator.of(context).pop(),
                ),
              ),
              AnimatedPositioned(
                duration: const Duration(milliseconds: 300),
                top: _showControls ? 8 : -60,
                left: 8,
                child: IconButton(
                  icon: const Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24),
                  onPressed: () => Navigator.of(context).pop(),
                ),
              ),
              AnimatedPositioned(
                duration: const Duration(milliseconds: 300),
                bottom: _showControls ? 0 : -100,
                left: 0,
                right: 0,
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
                  color: const Color(0x66000000),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      Slider(
                        value: widget.controller.value.position?.inSeconds.toDouble() ?? 0,
                        max: widget.controller.value.duration?.inSeconds.toDouble() ?? 1.0,
                        onChanged: (value) async {
                          await widget.controller.seekTo(Duration(seconds: value.round()));
                          _showControlsTemporarily();
                        },
                      ),
                      Row(
                        children: [
                          IconButton(
                            icon: Icon(
                              (widget.controller.value.isPlaying ?? false) ? Icons.pause_rounded : Icons.play_arrow_rounded,
                              color: Colors.white,
                            ),
                            onPressed: () async {
                              if (widget.controller.value.isPlaying ?? false) {
                                await widget.controller.pause();
                              } else {
                                await widget.controller.play();
                              }
                              _showControlsTemporarily();
                            },
                          ),
                          IconButton(
                            icon: const Icon(Icons.replay_10_rounded, color: Colors.white),
                            onPressed: () async {
                              final currentPos = widget.controller.value.position ?? Duration.zero;
                              final newPos = currentPos - const Duration(seconds: 10);
                              await widget.controller.seekTo(newPos.isNegative ? Duration.zero : newPos);
                              _showControlsTemporarily();
                            },
                          ),
                          IconButton(
                            icon: const Icon(Icons.forward_10_rounded, color: Colors.white),
                            onPressed: () async {
                              final currentPos = widget.controller.value.position ?? Duration.zero;
                              final duration = widget.controller.value.duration ?? Duration.zero;
                              final newPos = currentPos + const Duration(seconds: 10);
                              await widget.controller.seekTo(newPos > duration ? duration : newPos);
                              _showControlsTemporarily();
                            },
                          ),
                          const Spacer(),
                          Text(
                            '${_formatDuration(widget.controller.value.position ?? Duration.zero)} / ${_formatDuration(widget.controller.value.duration ?? Duration.zero)}',
                            style: const TextStyle(color: Colors.white),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }

  String _formatDuration(Duration duration) {
    String twoDigits(int n) => n.toString().padLeft(2, '0');
    final hours = twoDigits(duration.inHours);
    final minutes = twoDigits(duration.inMinutes % 60);
    final seconds = twoDigits(duration.inSeconds % 60);
    return hours == '00' ? '$minutes:$seconds' : '$hours:$minutes:$seconds';
  }
}

class _FullScreenChewie extends StatefulWidget {
  final ChewieController controller;
  final VideoPlayerController videoController;
  const _FullScreenChewie({required this.controller, required this.videoController});

  @override
  State<_FullScreenChewie> createState() => _FullScreenChewieState();
}

class _FullScreenChewieState extends State<_FullScreenChewie> {
  ChewieController? _fsController;
  @override
  void initState() {
    super.initState();
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
    SystemChrome.setPreferredOrientations(const [
      DeviceOrientation.landscapeLeft,
      DeviceOrientation.landscapeRight,
    ]);
    _fsController = ChewieController(
      videoPlayerController: widget.videoController,
      autoPlay: false,
      looping: false,
      allowFullScreen: false,
      allowPlaybackSpeedChanging: true,
    );
  }

  @override
  void dispose() {
    try { _fsController?.dispose(); } catch (_) {}
    SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
    SystemChrome.setPreferredOrientations(const [
      DeviceOrientation.portraitUp,
    ]);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double ar = widget.videoController.value.aspectRatio == 0
        ? 16 / 9
        : widget.videoController.value.aspectRatio;
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: [
          Center(
            child: AspectRatio(
              aspectRatio: ar,
              child: _fsController == null ? const SizedBox.shrink() : Chewie(controller: _fsController!),
            ),
          ),
          Positioned(
            top: 8,
            right: 8,
            child: IconButton(
              icon: const Icon(Icons.fullscreen_exit_rounded, color: Colors.white, size: 28),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ),
          Positioned(
            top: 8,
            left: 8,
            child: IconButton(
              icon: const Icon(Icons.arrow_back_ios_new_rounded, color: Colors.white, size: 24),
              onPressed: () => Navigator.of(context).pop(),
            ),
          ),
        ],
      ),
    );
  }
}
